So, we have a Player who can shoot bullets at an enemy to destroy him, and should the Player touch the Enemy, the game restarts. Now, then - let's make the enemy a little more assertive.
We'll modify the code to make the enemy move towards the Player, making him more of a threat. It's not too hard to do, at all, actually. While the enemy isn't very difficult to make, he demonstrates a few good concepts that can be reused in many ways. So, let's take a look at the Enemy's source code.
from bge import logic from bge import events from math import * from mathutils import * def Enemy(): cont = logic.getCurrentController() sce = logic.getCurrentScene() obj = cont.owner bulletcol = cont.sensors['BulletCol'] player = sce.objects['Player'] def Init(): if not 'init' in obj: obj['init'] = 1 obj['hp'] = 3 # Set your HP at the beginning obj['target'] = player # Set your target to default to the Player obj['movespd'] = 0.1 def Update(): if bulletcol.positive: obj['hp'] -= 1 # Decrement your HP one bullet = bulletcol.hitObject # Get the bullet you collided with bullet.endObject() # And destroy it tp = obj['target'].position op = obj.position a = atan2(op.y - tp.y, op.x - tp.x) + (pi * 0.5)
# Get the angle between the enemy
# and the target (defaults to the player), and add half a rotation to it (line above) o = Euler([0, 0, a])
# Create a simple Euler angle representing the rotation of the Enemy (line above)
obj.worldOrientation = o
# And set the enemy's orientation to the angle (face the target; line above) obj.applyMovement([0, obj['movespd'], 0], 1) # Move towards the Player if obj['hp'] <= 0: # If you have 0 HP obj.endObject() # Then destroy yourself Init() Update()
As you can see, there's not too much change here. First, we import everything from the mathutils and math modules. This way, we don't have to type so much. After this, we go right into the Enemy function definition.
player = sce.objects['Player']
After this, we get the player as a variable reference. After this, in the Init() function, we set the enemy's target to default to the Player. Also, we define a new movespd variable that designates how fast the enemy will move toward the Player. The biggest change is really only in this portion in the Update() function:
tp = obj['target'].position
op = obj.position a = atan2(op.y - tp.y, op.x - tp.x) + (pi * 0.5) o = Euler([0, 0, a]) # Create a simple Euler angle obj.worldOrientation = o # And set it to the angle obj.applyMovement([0, obj['movespd'], 0], 1)
As you can see, we get the target's position and the Enemy object's position, as well. If you recall your high-school geometry, a full rotation is formed (in radians) by 2 pi. So, half a rotation is pi, and a quarter of a rotation, or a 90-degree turn, is half of pi. Also, to get the angle from one point to another, we can use the arc tangent function ( atan2() ). By subtracting the target's (Player's) position from the Enemy's position, we can get the angle from the Enemy to the target. We get the angle from the Enemy to the Player, and then rotate it by half of pi to make it face the correct direction.
Once we have the correct angle, we create a new angle with the Euler() function - it's really mathutils.Euler(), but since we imported all from the mathutils module, we don't have to write that part. We set it to rotate on the Z-axis, so that he faces the Player. Finally, we apply a motion on the local axis, toward the direction the Enemy is facing (toward the Player). That's it - the Enemy will now track the Player around until one of them gets it. >:D
Anyway, that's it. Download Part 8 of the MazeCrawl source code here.
Mirror 1: MediaFire
Mirror 2: Box.net