Create a flash game like Security – part 2

Read all posts about "" game

July 27th update: part 3 released

This is the second part of the creation of a flash game like Security. In the first part we saw how to create the maze, the player and the “cop”.

Now, we’ll see how to create a “smart” cop.

I did not like how the orginal game managed the “line of sight”, so I decided to try coding something different and closer to the reality (well, if a blue circle is supposed to be a “cop” we are not so close to reality, anyway…).

The line of sight

Let’s imagine what is a “line of sight”: basically, it’s a line that connets the “cop” to the objects the cop can see. In our case, the only thing we need our cop to see, is the player. So, in next example, the line of sight is a line that goes from the cop to the player.

I created an object representing a green line and I dragged to the scene, instancing it as “line”.

Then, in the COP actions I wrote this actionscript

onClipEvent (enterFrame) {
	dist_x = _root.hero._x-_x;
	dist_y = _root.hero._y-_y;
	angle = Math.atan(dist_y/dist_x)/(Math.PI/180);
	if (dist_x<0) {
		angle += 180;
	}
	if (dist_x>=0 && dist_y<0) {
		angle += 360;
	}
	_root.line._x = _x;
	_root.line._y = _y;
	_root.line._rotation = angle;
}

Lines 2-10: Determine the angle between the cop and the player using trigonomerty basics as explained in Create a flash draw game like Line Rider or others - part 3 tutorial.

Lines 11-12: Place the line _x and _y in the same position of cop's _x and _y

Line 13: Rotates the line of angle degrees

Try to move the player, and you will see the cop line of sight following him.

Hey! our cop is not Superman! He can't see through walls!

The line of sight (limited by walls)

We have to have the cop see the player only when the line of sight hits the player before hitting any wall.

The new cop actionscript is:

onClipEvent (enterFrame) {
	dist_x = _root.hero._x-_x;
	dist_y = _root.hero._y-_y;
	dist = Math.sqrt(dist_x*dist_x+dist_y*dist_y);
	angle = Math.atan(dist_y/dist_x)/(Math.PI/180);
	if (dist_x<0) {
		angle += 180;
	}
	if (dist_x>=0 && dist_y<0) {
		angle += 360;
	}
	wall_collision = 0;
	for (x=1; x<=dist; x++) {
		point_x = _x+x*Math.cos(angle*Math.PI/180);
		point_y = _y+x*Math.sin(angle*Math.PI/180);
		if (_root.wall.hitTest(point_x, point_y, true)) {
			wall_collision = 100;
			break;
		}
	}
	_root.line._x = _x;
	_root.line._y = _y;
	_root.line._rotation = angle;
	_root.line._alpha = 100-wall_collision;
}

Line 12: Declare a variable called wall_collision to zero

Line 13: Loop to be executed as much times as the distance between the cop and the player, in pixels. This can be CPU expensive if you have large stages or lots of cops. In this case, you can adjust the "x++" condition with, in example, "x+=3". This will make the process faster but less accurate. It's up to you to find the right gameplay balance.

Lines 14-15: Determining the x and y coordinates of the x-th pixel from the cop in direction of the player, using trigonomerty

Line 16: Test the collision between the pixel just determined and the wall

Lines 17-18: If the test is positive, then the cop, looking in the direction of the player, won't see the player because there is a wall in the middle. So I set the wall_collision variable to 100 and break the loop to save CPU

Line 24: Set the alpha of the line at 100-wall_collision... in other words to opaque if the cop sees the player, and transparent if the cop does not see the player. This is only for testing the line of sight, of course... in a real game you can make the cop fire (we'll se how in another tutorial) or call a game over screen.

Try to move around the screen and you will see the cop will spot you only if there are no walls between the player and the cop.

You may say: why don't just perform an hit test between the line of sight and the walls, having the line of sight going exactly from the cop to the player? This is an idea, but will prevent to code special stuff such as mirrors, special walls that deflects the line of sight in a strange way, and so on.

Once the cop sees correctly, it's time to make him patrol the area

The line of sight (limited by walls) of a moving cop

To have the cop patrolling the area, I removed the cop movieclip from the stage and inserted another one, called cop_patrol.

This movieclip consists in the cop himself moving around using a guide layer.

So in the main scene we do not have the cop movieclip but the cop_patrol one. In the cop movieclip (inside the cop_patrol) the actionscript is:

onClipEvent (enterFrame) {
	dist_x = _root.hero._x-(_x+_root.cop_patrol._x);
	dist_y = _root.hero._y-(_y+_root.cop_patrol._y);
	dist = Math.sqrt(dist_x*dist_x+dist_y*dist_y);
	angle = Math.atan(dist_y/dist_x)/(Math.PI/180);
	if (dist_x<0) {
		angle += 180;
	}
	if (dist_x>=0 && dist_y<0) {
		angle += 360;
	}
	wall_collision = 0;
	for (x=1; x<=dist; x++) {
		point_x = (_x+_root.cop_patrol._x)+x*Math.cos(angle*Math.PI/180);
		point_y = (_y+_root.cop_patrol._y)+x*Math.sin(angle*Math.PI/180);
		if (_root.wall.hitTest(point_x, point_y, true)) {
			wall_collision = 100;
			break;
		}
	}
	
	_root.line._x = (_x+_root.cop_patrol._x);
	_root.line._y = (_y+_root.cop_patrol._y);
	_root.line._rotation = angle;
	_root.line._alpha = 100-wall_collision;
}

As you may notice, the actionscript is the same as before, but all pixel measurements are taken adding to the _x and _y values (the cop position) the _root.cop_patrol_x and _root.cop_patrol_y values (the position of the cop_patrol movieclip).

I had to do this because the _x and _y values are relative to the parent movieclip, in this case the cop_patrol movieclip... so I have to add to these values the position of the cop_patrol movieclip to have the real coordinates.

Now we have a patrolling cop that will see the player only if there are no walls between the player and the cop.

That's almost perfect, but I didn't know cops had eyes on their back... so we need the cop to see only in the direction they are walking.

The line of sight (limited by walls) of a moving cop seeing only in front of him

We need to determine the direction the cop is walking in. I did changing the cop's actionscript in this way:

onClipEvent (enterFrame) {
	dist_x = _root.hero._x-(_x+_root.cop_patrol._x);
	dist_y = _root.hero._y-(_y+_root.cop_patrol._y);
	dist = Math.sqrt(dist_x*dist_x+dist_y*dist_y);
	angle = Math.atan(dist_y/dist_x)/(Math.PI/180);
	if (dist_x<0) {
		angle += 180;
	}
	if (dist_x>=0 && dist_y<0) {
		angle += 360;
	}
	wall_collision = 0;
	for (x=1; x<=dist; x++) {
		point_x = (_x+_root.cop_patrol._x)+x*Math.cos(angle*Math.PI/180);
		point_y = (_y+_root.cop_patrol._y)+x*Math.sin(angle*Math.PI/180);
		if (_root.wall.hitTest(point_x, point_y, true)) {
			wall_collision = 100;
			break;
		}
	}
	dist_old_x = _x-old_x;
	dist_old_y = _y-old_y;
	cop_direction = Math.atan(dist_old_y/dist_old_x)/(Math.PI/180);
	if (dist_old_x<0) {
		cop_direction += 180;
	}
	if (dist_old_x>=0 && dist_old_y<0) {
		cop_direction += 360;
	}
	old_x = _x;
	old_y = _y;
	sight = angle-cop_direction;
	if (((sight<30)and(sight > -30))or(sight>330)) {
		_root.line._x = (_x+_root.cop_patrol._x);
		_root.line._y = (_y+_root.cop_patrol._y);
		_root.line._rotation = angle;
		_root.line._alpha = 100-wall_collision;
	} else {
		_root.line._alpha = 0;
	}
}

Lines 21-22: Determine the distance from the current cop position and the previous cop position. In the first frame, these values will be undefined.

Lines 23-29: Determine cop direction using trigonometry

Lines 30-31: Save the current cop position (that will be used as the old cop position next time lines 21-22 will be called)

Line 32: Determine the angle of sight, according to the cop direction and the absolute angle between the cop and the player

Lines 33-40: Determine if the angle of sight is in the cone of 60 degrees in the cop direction. In that case, show the line (if there are not walls between the cop and the player). If the angle of sight is not in the cone, don't show the line.

Now you will notice the cop will "see" you only if you are standing in front of him.

This is how a line of sight should be.

Download the source codes and give me feedback, then learn how to place exits and have a second agent in next step

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

214 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers